﻿// Written by Dale J Williams.
// Licensed under MPL 1.1 unless otherwise specified. 
// http://www.mozilla.org/MPL/MPL-1.1.html

package engineDJW.load {
	
	import engineDJW.interfaces.ILoadable;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.media.Sound;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;
	
	/**
	 * ...
	 * @author Dale J Williams
	 */
	public class LoadManager extends EventDispatcher {
		
		private var _cue			:Vector.<ILoadable>;
		private var _items			:Dictionary;
		private var _urls			:Dictionary;
		private var _loading		:Boolean;
		private var _itemsLoading	:int;
		private var _onComplete		:Function;
		
		public function LoadManager() {
			init();
		}
		
		private function init():void {
			_cue = new Vector.<ILoadable>;
			_items = new Dictionary();
			_urls = new Dictionary();
		}
		
		public function addToCue($url:String, $name:String = null, $loaderType:Class = null):void {
			if (_urls[$url]) {
				_items[$name] = _urls[$url];
				return;
			}
			if (!$name) $name = $url;
			var ext:String = $url.substr($url.lastIndexOf(".") + 1);
			var loadable:ILoadable;
			if ($loaderType) loadable = new $loaderType();
			else switch (ext.toLowerCase()) {
				case "mp3":
					loadable = new SoundLoader();
					break;
				case "jpg":
				case "jpeg":
				case "png":
				case "gif":
				case "swf":
					loadable = new DisplayLoader();
					break;
				default:
					loadable = new DataLoader();
			}
			loadable.url = $url;
			_cue.push(loadable);
			_items[$name] = loadable;
			_urls[$url] = loadable;
			trace($name + " " + getQualifiedClassName(loadable) + " (" + $url + ") added to cue.");
		}
		
		public function addObjectToCue($urls:Object):void {
			for (var url:String in $urls)
				addToCue($urls[url], url);
		}
		
		public function getLoader($name:String):ILoadable {
			return ILoadable(_items[$name]);
		}
		
		public function getData($name:String):* {
			return DataLoader(_items[$name]).data;
		}
		
		public function getBytes($name:String):ByteArray {
			return ByteArray(DataLoader(_items[$name]).data);
		}
		
		public function getSound($name:String):Sound {
			return SoundLoader(_items[$name]).sound;
		}
		
		public function getContent($name:String):DisplayObject {
			return DisplayLoader(_items[$name]).content;
		}
		
		public function getContentUnique($name:String):DisplayObject {
			var contentClass:Class = getContentClass($name);
			return new contentClass() as DisplayObject; 
		}
		
		public function getContentChildUnique($name:String):DisplayObject {
			var contentClass:Class = Object(DisplayObjectContainer(getContent($name)).getChildAt(0)).constructor;
			return new contentClass() as DisplayObject; 
		}
		
		public function getContentClass($name:String):Class {
			return Object(getContent($name)).constructor;
		}
		
		public function getBitmapData($name:String):BitmapData {
			return Bitmap(DisplayLoader(_items[$name]).content).bitmapData;
		}
		
		public function load():void {
			_itemsLoading = _cue.length;
			_loading = true;
			loadNext();
		}
		
		private function loadNext():void {
			if (_cue.length <= 0) return;
			trace("loaded " + Math.floor(loadPercent * 100) + "%. " + _cue.length + " remain.");
			var loader:ILoadable = ILoadable(_cue.shift());
			loader.addEventListener(Event.COMPLETE, loadCheck);
			loader.load();
		}
		
		private function loadCheck(e:Event):void {
			_items[e.target.url] = e.target;
			if (_cue.length > 0) loadNext();
			else loadComplete();
		}
		
		private function loadComplete():void {
			trace("load complete.");
			_loading = false;
			dispatchEvent(new Event(Event.COMPLETE));
			if (_onComplete != null) _onComplete();
			//_onComplete = null;
		}
		
		public function get loading():Boolean { return _loading; }
		
		public function get loadPercent():Number {
			return (_itemsLoading - _cue.length) / (_itemsLoading);
		}
			
		public function set onComplete(value:Function):void {
			_onComplete = value;
		}
		
	}
	
}